﻿package {
	
	import engine.base.sim.SimObject;
	import engine.base.sim.SimSet;
	import engine.base.sim.Sim;
	import engine.base.command.ICommand;
	import engine.gui.LoginScreen;
	import it.gotoandplay.smartfoxserver.data.Room;
	import it.gotoandplay.smartfoxserver.data.User;

	import engine.game.Camera;
	import engine.game.world.Tile;
	import engine.gui.ChatBox;
	import engine.gui.SideBar;
	import engine.input.Controller;
	import engine.game.player.commands.WalkPlayer;
	import engine.base.GameBase;
	import engine.game.world.Map;
	import engine.game.player.Player;
	import engine.network.GameSocketClient;
	import engine.network.events.*;
	import engine.ticker.Ticker;
	import engine.ticker.TickerEvent;
	import flash.display.Sprite;
	import engine.managers.AssetManager;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import engine.input.Key;
	import flash.events.Event;
	import engine.game.Constants;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.*;
	import flash.ui.Keyboard;
	import org.flashdevelop.utils.FlashConnect;
	import it.gotoandplay.smartfoxserver.*;
	
	/**
	* Main entry point for the application.
	* @author Jon Smelquist
	*/
	public class Main extends Sprite{
		
		protected var player:Player;
		protected var m_Players:Array;
		protected var map:Map;
		protected var ticker:Ticker;
		protected var controller:Controller;
		protected var chatBox:ChatBox;
		protected var sideBar:SideBar; 
		protected var loginScreen:LoginScreen; 
		protected var remotePlayers:Object;
		
		// Smart Fox Server
		protected var smartFox:SmartFoxClient;
		
		protected const STATE_SYSTEM_LOADING:int = 0;
		protected const STATE_SYSTEM_CONNECTING_TO_SERVER:int = 1;
		protected const STATE_MAIN_GAMEPLAY:int = 2;
		protected var gameState:int = STATE_SYSTEM_LOADING;
		
		public function Main() {		
			// Call our init function
			init();
		}
		
		private function init():void
		{
			// Initialize our server connection, calls the "connectionMade" function
			// upon connection which allows us to move State to wait for a player ID back
			// from the server.
			smartFox = new SmartFoxClient();
			smartFox.addEventListener(SFSEvent.onConnection, onConnected);
			smartFox.addEventListener(SFSEvent.onExtensionResponse, onExtResponse);
			smartFox.addEventListener(SFSEvent.onJoinRoom, onJoinRoomHandler);
			smartFox.addEventListener(SFSEvent.onRoomListUpdate, onRoomListUpdateHandler);
			smartFox.addEventListener(SFSEvent.onUserEnterRoom, onUserEnterRoomHandler);
			smartFox.addEventListener(SFSEvent.onUserLeaveRoom, onUserLeaveRoomHandler);
			smartFox.addEventListener(SFSEvent.onPublicMessage, onPublicMessageHandler);
			smartFox.connect("67.23.25.65");
		
			// Initialize local player object container
			m_Players = new Array();
			remotePlayers = {};
			
			
			// Initialize controller object
			controller = new Controller();
			
			// Initialize keyboard handler
			Key.initialize( stage );
			
			// Create a camera and bind it to the main surface
			Camera.getInstance().bind(this);
			
			// Create and bind our GUI elements
			chatBox = new ChatBox();
			this.addChild(chatBox);
			sideBar = new SideBar();
			addChild(sideBar);
			loginScreen = new LoginScreen(smartFox);
			addChild(loginScreen);
			
			// Create a new ticker running at 21ms
			ticker = new Ticker(21);
			ticker.addEventListener( TickerEvent.TICK, tick );

		}
	
		protected function onExtResponse(evt:SFSEvent):void
		{
			var type:String = evt.params.type;
			var data:Object = evt.params.dataObj;
			var command:String = data._cmd;
			
			switch(type)
			{
				case "xml":
					if (command == "logOK")
					{
						// Login Successful
						chatBox.appendLine("Joined Game Successfully. Player ID: " + data.id);
						// create our local player object
						player = new Player(AssetManager.YHETI, data.id, data.name);
						m_Players.push(player);
						
						// Initialize our map object, using map name from server
						map = new Map(data.map);
						map.registerObject("CurrentMap");
					}
					else if (command == "logKO")
					{
						// Login Failed
						chatBox.appendLine("Login Failed!");
					}
					break;
				case "str":
					break;
			}
			
		}
		
		protected function onRoomListUpdateHandler(evt:SFSEvent):void
		{
			smartFox.joinRoom(map.mapName);
		}
		
		protected function onPublicMessageHandler(evt:SFSEvent):void
		{
			chatBox.appendLine(evt.params.sender.getName() + " said: " + evt.params.message);
		}
		
		protected function onJoinRoomHandler(evt:SFSEvent):void
		{
			var joinedRoom:Room = evt.params.room;
			var users:Array = joinedRoom.getUserList();
			var newPlayer:Player;
			for (var u:String in users)
			{
				if (users[u].getId() != player.id)
				{
					newPlayer = new Player(AssetManager.YHETI, users[u].getId().toString(), users[u].getName());
					newPlayer.setPlayerPosition(new Point(5*32,5*32), 1);
					m_Players.push(newPlayer);
					remotePlayers[users[u].getId().toString()] = newPlayer;
				}
			}
			startGame();
		}
		
		
		protected function onUserEnterRoomHandler(evt:SFSEvent):void
		{
			var user:User = evt.params.user;
			chatBox.appendLine("New Player Joined: " + user.getName());
			
			var myNewPlayer:Player = new Player(AssetManager.GUARD, user.getId().toString(), user.getName());
			myNewPlayer.setPlayerPosition(new Point(5*32,5*32), 1);
			m_Players.push(myNewPlayer);
			remotePlayers[user.getId().toString()] = myNewPlayer;
		}
		
		
		protected function onUserLeaveRoomHandler(evt:SFSEvent):void
		{
			var userName:String = evt.params.userName;
			var userId:String = evt.params.userId;
			chatBox.appendLine(userName+" disconnected.");
			
			var discPlayer:Player = remotePlayers[userId];
			var index:int = m_Players.indexOf(discPlayer);
			m_Players.splice(index, 1);
			remotePlayers[userId] = null;
		}
		
		protected function onPlayerStateChanged(myEvent:SocketResponseEvent):void 
		{
			var myPlayer:Player = remotePlayers[myEvent.parameters.player_id];
			
			for(var i:String in myEvent.parameters.properties)
			{
				myPlayer[i] = myEvent.parameters.properties[i];
			}
		}
		
		protected function onConnected(success:Boolean):void
		{
			if (success)
			{	
               chatBox.appendLine("Connected to Server.");
			}
			else
			{
               chatBox.appendLine("Can't connect.");
			}
		}
		
		protected function sendPlayerChanges(player:Player):void
		{			
			stage.dispatchEvent(new SocketRequestEvent(SocketRequestEvent.CHANGE_PLAYER_STATE, 1,player.changedItems));
			player.clearDirty();
		} 
		
		protected function startGame():void
		{
			loginScreen.visible = false;
			Map.loadMap(map, mapLoaded);
			controller.bindCommand(Keyboard.LEFT, new WalkPlayer(player, Constants.WEST));
			controller.bindCommand(Keyboard.RIGHT, new WalkPlayer(player, Constants.EAST));
			controller.bindCommand(Keyboard.UP, new WalkPlayer(player, Constants.NORTH));
			controller.bindCommand(Keyboard.DOWN, new WalkPlayer(player, Constants.SOUTH));
			
			ticker.start();
		}
		
		private function tick(evt:TickerEvent):void
		{
			
			handleInput(evt);
			
			switch (gameState) {
				case STATE_MAIN_GAMEPLAY:
					for each (var plyr:Player in m_Players)
					{
						plyr.processTick(evt.interval);
					}
			
					map.processTick(evt.interval);     

					m_Players.sortOn("y", Array.NUMERIC);
					var cam:Camera = Camera.getInstance();
					cam.lockCanvas();
					cam.clearScene();
					cam.alignCamera(player);
					cam.render(map.base);
					cam.render(map.creatures);
					cam.render(m_Players);
					cam.render(map.overlay);
					cam.unlockCanvas();
					
					if (player.dirty == true)
					{
						sendPlayerChanges(player);
					}
					
					break;
			}
			
			
		}
		
		private function mapLoaded(e:Event):void
		{
			player.setPlayerPosition(map.playerSpawn, map.playerSpawnDir);
			gameState = STATE_MAIN_GAMEPLAY;
		}
		
		private function handleInput( evt:TickerEvent ):void
		{
			switch (gameState) {
				case STATE_MAIN_GAMEPLAY:
					if ( Key.isDown( Keyboard.LEFT ) ) {
						controller.executeCommand( Keyboard.LEFT );
					}
					else if ( Key.isDown( Keyboard.RIGHT ) ) {
						controller.executeCommand( Keyboard.RIGHT );
					}
					else if ( Key.isDown( Keyboard.UP ) ) {
						controller.executeCommand( Keyboard.UP );
					}
					else if ( Key.isDown( Keyboard.DOWN ) ) {
						controller.executeCommand( Keyboard.DOWN );
					}
					else if ( Key.isDown( Keyboard.ENTER ) ) {
						var txt:String = chatBox.getText();
						if (txt != "")
						{
							smartFox.sendPublicMessage(txt);	
						}
					}
					
			}
		}
		
	}
	
}